const PENDING = 'pending';  //等待
const FULFILLED = 'fuleilled';  //成功
const REJECTED = 'rejected';  //失败



class MyPromise {
	// 执行器  回调函数
	constructor (executor) {
		try {
			// 捕获执行器错误
			executor(this.resolve, this.reject)
		} catch(e) {
			this.reject(e)
		}
		
	}
	// promise状态
	status = PENDING;
	// 保存成功后的值
	value = undefined;
	// 保存失败后的值
	reason = undefined;

	// 为了处理异步情况 
	// 成功回调
	successCallBack = [];
	// 失败回调
	failCallBack = [];

	// 箭头函数直接调用
	resolve = value =>{
		// 判断状态 不是等待状态就阻止往下执行
		if(this.status !== PENDING) return
		// 修改为成功的状态
		this.status = FULFILLED;
		// 保存成功的值
		this.value = value;
		// 判断调用成功回调时 回调是否已经存在 取出第一条执行 依次调用
		while (this.successCallBack.length) this.successCallBack.shift()()
	}

	reject = reason =>{
		// 判断状态 不是等待状态就阻止往下执行
		if(this.status !== PENDING) return
		// 修改为失败的状态
		this.status = REJECTED;
		// 保存失败的值
		this.reason = reason;
		// 判断调用失败回调时 回调是否已经存在 取出第一条执行 依次调用
		while (this.failCallBack.length) this.failCallBack.shift()()
	}

	then (successCallBack, failCallBack){
		// 判断成功回调是否有参数 没有则value => value
		successCallBack = successCallBack ? successCallBack : value => value;
		// 判断失败回调是否有参数 没有则传递到下一个then
		failCallBack = failCallBack ? failCallBack : reason => { throw reason };
		// 返回promise对象
		let promise2 = new MyPromise((resolve, reject) =>{
			if(this.status === FULFILLED){
				// 把执行结果放setTimeout 0 
				// 变成异步 这样就能拿到promise2了
				setTimeout(() => {
					try {
						// 捕获then方法的错误信息
						// 拿到then方法传递的值
						let x = successCallBack(this.value)
						// 把拿到的值传给下一个then方法
						// 判断 x 的值是普通值还是promise对象
						// 如果是promise对象 则判断结果是调用resolve ，还是reject
						resolvePromise(promise2, x, resolve, reject)
					} catch(e) {
						reject(e)
					}
				}, 0)
			}else if(this.status === REJECTED){
				// 处理失败
				// 把执行结果放setTimeout 0 
				// 变成异步 这样就能拿到promise2了
				setTimeout(() => {
					try {
						// 捕获then方法的错误信息
						// 拿到then方法传递的值
						let x = failCallBack(this.reason)
						// 把拿到的值传给下一个then方法
						// 判断 x 的值是普通值还是promise对象
						// 如果是promise对象 则判断结果是调用resolve ，还是reject
						resolvePromise(promise2, x, resolve, reject)
					} catch(e) {
						reject(e)
					}
				}, 0)
			}else {
				// 异步等待的时候
				this.successCallBack.push( () => {
					// 加入捕获错误处理 和 异步处理
					setTimeout(() => {
						try {
							// 捕获then方法的错误信息
							// 拿到then方法传递的值
							let x = successCallBack(this.value)
							// 把拿到的值传给下一个then方法
							// 判断 x 的值是普通值还是promise对象
							// 如果是promise对象 则判断结果是调用resolve ，还是reject
							resolvePromise(promise2, x, resolve, reject)
						} catch(e) {
							reject(e)
						}
					}, 0)
				} );
				this.failCallBack.push( () => {
					// 加入捕获错误处理 和 异步处理
					setTimeout(() => {
						try {
							// 捕获then方法的错误信息
							// 拿到then方法传递的值
							let x = failCallBack(this.reason)
							// 把拿到的值传给下一个then方法
							// 判断 x 的值是普通值还是promise对象
							// 如果是promise对象 则判断结果是调用resolve ，还是reject
							resolvePromise(promise2, x, resolve, reject)
						} catch(e) {
							reject(e)
						}
					}, 0)
				} );
			}
		})
		return promise2
	}

	static all (array){
		//解决异步并发问题 可以按数组顺序得到对应的结果
		// 存储待处理结果
		let result = [];
		// 计算处理次数
		let index = 0;
		// all 返回的是promise对象
		return new MyPromise((resolve, reject) => {
			// 把执行结果放进result
			function addData (key, value){
				result[key] = value;
				index++;
				// 当全部回调执行完成 则抛出成功
				if(index === array.length){
					resolve(result)
				}
			}
			// 遍历处理array
			for (let i = 0; i < array.length; i++) {
				let current = array[i];
				// 判断是否为promise对象
				if(current instanceof MyPromise){
					// promise对象 成功则执行addData 失败调用reject
					current.then(value => addData(i, value), reason => reject(reason))
				}else {
					// 普通值
					addData(i, array[i])
				}
			}
		})
	}

	static resolve (value) {
		//如果传入的值是promise 直接返回
		// 传入的是值 则创建promise对象
		if(value instanceof MyPromise){
			return value
		} else {
			return new MyPromise(resolve => resolve(value))
		}
	}

	finally (callback) {
		// 从then方法中能拿到执行结果
		// finally 返回promise对象
		// finally 会执行callback方法
		// finally 可以在下一次then方法中拿到成功或失败的结果
		return this.then(value => {
			return MyPromise.resolve(callback()).then(() => value)
		}, reason => {
			return MyPromise.resolve(callback()).then(() => { throw reason })
		})
	}

	catch (failCallBack){
		// 返回失败promise
		return this.then(undefined, failCallBack)
	}
}

function resolvePromise (promise2, x, resolve, reject){
	// 判断是否为then是否返回为当前对象
	// 防止循环调用
	if (promise2 === x) {
		return reject(new TypeError('Chaining cycle detected for promise #<promise>'))
	}
	// 判断then的值是否为promise对象
	if(x instanceof MyPromise) {
		x.then(resolve, reject);
	} else {
		resolve(x);
	}
}

module.exports = MyPromise;